/*
   Copyright (C) 2022 Ivan Polyakov

   This file is part of fltube.

   fltube is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   fltube is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

/*! \file
 * \details This is a cURL wrapper for interacting with the Invidious API.
 *          It's provides you with high-level functions for selecting
 *          an instance of the Invidious API (see \ref invid_init)
 *          and making requests such as fetching popular videos
 *          (see \ref invid_getpop).
 *
 *          Example:
 *          \code{.c}
 *          #include <invidious.h>
 *          #include <stdio.h>
 *
 *          static void popcb(cJSON *response, void *userdata)
 *          {
 *              char *str = cJSON_Print(response);
 *              puts(str);
 *          }
 *
 *          int main()
 *          {
 *              invid_t client;
 *              int status;
 *
 *              // protocol required
 *              status = invid_init(&client, "https://yewtu.be");
 *
 *              if (status) {
 *                  fputs(invid_strerr(status), stderr);
 *                  return status;
 *              }
 *
 *              invid_getpop(client, popcb, NULL);
 *
 *              invid_cleanup(client);
 *              return 0;
 *          }
 *          \endcode
 */

#ifndef FLTUBE_INVIDIOUS_H_ENTRY
#define FLTUBE_INVIDIOUS_H_ENTRY

#ifdef __cplusplus
extern "C" {
#endif

#include <cjson/cJSON.h>
#include <curl/curl.h>

/*!
 * \brief          Response callback type.
 * \details        Callbacks of this type are used in requests to tell you
 *                 when the request has completed and what is returned
 *                 as a result.
 * \param response Response to the request in JSON format.
 * \param userdata Your data that you can pass to the callback.
 *
 * Example:
 * \code{.c}
 * void my_callback(cJSON *response, void *userdata)
 * {
 *     char *value = cJSON_GetObjectItemCaseSensitive(response, "someField");
 *     puts(value);
 * }
 *
 * ...
 * invid_getpop(client, my_callback, (void*) my_data);
 * ...
 * \endcode
 * cJSON library: https://github.com/DaveGamble/cJSON
 */
typedef void (*invid_rescb_t)(cJSON *response, void *userdata);

/*! \brief Invidious API struct. */
typedef struct _invidious_client_struct *invid_t;

/*!
 * \brief   Enumeration of error codes.
 * \details All error codes of this module are negative.
 *          So you can check the code and if it's positive
 *          it's a cURL error, not invidious.
 *
 *          If you get a negative (invidious) error code,
 *          you can get its description using \ref invid_strerr.
 *
 *          To find out what errors a function can return,
 *          you can look at its type.
 *          If it's \b inviderr_t it can only return invidious errors,
 *          if it's \b CURLcode it can only return cURL errors,
 *          and if it's an \b int it can return both types of errors.
 *          This is just a convention, so if you are the contributor,
 *          please follow it.
 *
 *          Error handling example:
 *          \code{.c}
 *          ...
 *          int status = invid_getpop(client, NULL, NULL);
 *          if (status < 0) {
 *              // invidious error
 *              fputs(invid_strerr(status), stderr);
 *          } else if (status > 0) {
 *              // curl error
 *              fputs(curl_easy_strerror(status), stderr);
 *          }
 *          ...
 *          \endcode
 */
typedef enum {
    inviderr_ok       =  0,   /*!< No error.                   */
    inviderr_alloc    = -1,   /*!< Out of memory.              */
    inviderr_curlinit = -2    /*!< Failed to initialize cURL   */
} inviderr_t;

/*!
 * \brief  Get the short description of the \a err.
 * \return Error description.
 */
const char *invid_strerr(inviderr_t err);

/*!
 * \brief        \ref invid_t initializer.
 * \brief        This function will allocate a new instance of \ref invid_t
 *               and fill its fields with initial values.
 *               Always instantiate \ref invid_t with this function.
 * \param client Pointer to allocate memory.
 * \param host   Invidious API instance host for sending requests.
 * \return       Status code.
 */
inviderr_t invid_init(invid_t *client, const char *host);

/*!
 * \brief        Clears the \ref invid_t instance.
 * \param client Invidious API struct instance to cleanup.
 */
void invid_cleanup(invid_t client);

/*!
 * \brief        Sets the Invidious API instance host.
 * \param client Invidious API struct instance.
 * \param host   Host for sending requests.
 */
inviderr_t invid_set_host(invid_t client, const char *host);

/*!
 * \brief          Gets popular videos.
 * \details        This function makes a request to `/api/v1/popular`
 *                 and calls the \a cb.
 * \param client   Invidious API struct instance.
 * \param cb       Callback to process response.
 * \param userdata Your data to be passed to the callback (\a cb).
 * \return         Status code.
 */
int invid_getpop(invid_t client, invid_rescb_t cb, void *userdata);

#ifdef __cplusplus
}
#endif

#endif /* FLTUBE_INVIDIOUS_H_ENTRY */
